﻿#include <functional>
#include <pluginGl.h>
#include <qobject.h>
#include <qsciscintilla.h>
#include <qstring.h>
#include <vcruntime.h>
#ifdef WIN32
#include <Windows.h>
#endif

#include "clang-format.h"

#define NDD_EXPORTDLL

#if defined( Q_OS_WIN )
#if defined( NDD_EXPORTDLL )
#define NDD_EXPORT __declspec( dllexport )
#else
#define NDD_EXPORT __declspec( dllimport )
#endif
#else
#define NDD_EXPORT __attribute__( ( visibility( "default" ) ) )
#endif

#ifdef __cplusplus
extern "C"
{
#endif

    NDD_EXPORT bool NDD_PROC_IDENTIFY( NDD_PROC_DATA* pProcData );
    NDD_EXPORT int NDD_PROC_MAIN( QWidget* pNotepad,
                                  const QString& strFileName,
                                  std::function< QsciScintilla*() > getCurEdit,
                                  std::function< bool( int, void* ) > pluginCallBack,
                                  NDD_PROC_DATA* procData );

#ifdef __cplusplus
}
#endif

static NDD_PROC_DATA s_procData;
static QWidget* s_pMainNotepad = nullptr;
std::function< QsciScintilla*() > s_getCurEdit;
std::function< bool( int, void* ) > s_invokeMainFun;

clang_format* clang_format_plugin;

bool NDD_PROC_IDENTIFY( NDD_PROC_DATA* pProcData )
{
    if ( pProcData == NULL )
    {
        return false;
    }
    pProcData->m_strPlugName = QObject::tr( "clang-format" );
    pProcData->m_strComment  = QObject::tr( "Plugin for formatting using clang-format" );

    pProcData->m_version = QString( "v1.0" );
    pProcData->m_auther  = QString( "SongZihui-sudo" );

    pProcData->m_menuType = 1;

    return true;
}

// 则点击菜单栏按钮时，会自动调用到该插件的入口点函数。
// pNotepad:就是CCNotepad的主界面指针
// strFileName:当前插件DLL的全路径，如果不关心，则可以不使用
// getCurEdit:从NDD主程序传递过来的仿函数，通过该函数获取当前编辑框操作对象QsciScintilla
// s_invokeMainFun: 可以回调NDD主程序中的功能函数，比如创建新文件功能等，根据需要可实时扩展。
// pProcData:如果pProcData->m_menuType = 0 ,则该指针为空；如果pProcData->m_menuType = 1，则该指针有值。目前需要关心s_procData.m_rootMenu
// 开发者可以在该菜单下面，自行创建二级菜单
int NDD_PROC_MAIN( QWidget* pNotepad,
                   const QString& strFileName,
                   std::function< QsciScintilla*() > getCurEdit,
                   std::function< bool( int, void* ) > pluginCallBack,
                   NDD_PROC_DATA* pProcData )
{
   

    // 务必拷贝一份pProcData，在外面会释放。
    if ( pProcData != nullptr )
    {
        s_procData = *pProcData;
    }

    s_pMainNotepad  = pNotepad;
    s_getCurEdit    = getCurEdit;
    s_invokeMainFun = pluginCallBack;

    clang_format_plugin = new clang_format(pNotepad);

    // 如果pProcData->m_menuType = 1;是自己要创建二级菜单的场景。则通过s_procData.m_rootMenu
    // 获取该插件的菜单根节点。 插件开发者自行在s_procData.m_rootMenu下添加新的二级菜单项目
    s_procData.m_rootMenu->addAction( "Format file", []() { clang_format_plugin->format(s_getCurEdit); } );

    s_procData.m_rootMenu->addAction( "Format selection",
                                      []() { clang_format_plugin->format_selection(s_getCurEdit); } );

    s_procData.m_rootMenu->addAction( "Settings",
                                      []() { clang_format_plugin->config(  ); } );

    clang_format_plugin->load_config(strFileName);

    return 0;
}

#ifdef WIN32
BOOL WINAPI DllMain( HINSTANCE hInst, DWORD fdwReason, LPVOID lpvReserved )
{
    switch ( fdwReason )
    {
        case DLL_PROCESS_ATTACH:
        case DLL_THREAD_ATTACH:
            break;
        case DLL_THREAD_DETACH:
            break;
        case DLL_PROCESS_DETACH:
            if ( NULL == lpvReserved )
            {
                // 做全局回收工作
            }
            break;
    }
    return TRUE;
}
#else
void onDllUnload( void )
{
    // 做全局回收工作
}
#endif
